﻿using Mimas.Core.Current;
using Mimas.Framework.Server.DomainObjects;
using Mimas.Framework.Server.DomainObjects.Mapping;
using Mimas.Framework.Shared.Data.CriteriaObjects;
using Mimas.Framework.Shared.Data.DataTransferObjects;
using Mimas.Framework.Shared.Data.EnumObjects;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Web;

namespace Mimas.Framework.Server.UserManagement
{
  public static class UserManagementBL
  {
    public static bool UserLogin(UserLoginCO login)
    {
      if (login == null) throw new FaultException(new FaultReason(""), new FaultCode("S0001"));

      CurrentUserDTO result = new CurrentUserDTO();
      login.UserName = login.UserName != null ? login.UserName.Trim().ToLower() : "";
      login.PassWord = login.PassWord != null ? login.PassWord.Trim().ToLower() : "";

      using (MIMASEntities db = new MIMASEntities())
      {
        DbSet<User> UserSet = db.Set<User>();
        DbSet<Person> PersonSet = db.Set<Person>();

        var Linq = from u in UserSet
                   join p in PersonSet on u.Id equals p.UserId
                   select new { user = u, person = p };

        if (!string.IsNullOrEmpty(login.UserName))
          Linq = Linq.Where(x => x.user.Username.ToLower() == login.UserName || x.user.EMail.ToLower() == login.UserName);

        var LinqResult = Linq.ToArray();

        if (LinqResult == null || !LinqResult.Any()) throw new FaultException(new FaultReason(""), new FaultCode("S0002"));
        else
        {
          var item = LinqResult.FirstOrDefault();
          if (item.user.Password.ToLower() != login.PassWord) throw new FaultException(new FaultReason(""), new FaultCode("S0003"));

          #region Validationn

          var userBans = SearchUserBanList(new UserBanListCO() { IsBanned = true, UserIds = new int[] { item.user.Id } });
          if (userBans.Any()) throw new FaultException(new FaultReason(userBans.FirstOrDefault().Explanation), new FaultCode("S0010"));

          if (!item.user.IsActive) throw new FaultException(new FaultReason(""), new FaultCode("S0011"));

          #endregion Validationn

          result.CellarNo = item.user.CellarNo;
          result.EMail = item.user.EMail;
          result.FullName = item.user.Fullname;
          result.Name = item.person.Name;
          result.PersonId = item.person.Id;
          result.SurName = item.person.Surname;
          result.UserId = item.user.Id;
          result.UserName = item.user.Username;
          result.UserType = (EUserType)item.user.UserTypeId;

          UserInfo.CurrentUser = result;
          using (var transaction = db.Database.BeginTransaction())
          {
            item.user.LastLoginDate = DateTime.Now;
            db.SaveChanges();
            transaction.Commit();
          }
        }
      }
      return true;
    }

    public static bool UserLogOut()
    {
      try
      {
        return UserInfo.UserLogOut();
      }
      catch
      {
        return false;
      }
    }



    public static UserDTO[] SearchUsers(UserCO criteria)
    {
      if (criteria == null) criteria = new UserCO();

      List<UserDTO> result = new List<UserDTO>();

      using (MIMASEntities db = new MIMASEntities())
      {
        DbSet<User> UserSet = db.Set<User>();

        var Linq = from u in UserSet select u;

        if (criteria.UserIds != null && criteria.UserIds.Any())
          Linq = Linq.Where(x => criteria.UserIds.Contains(x.Id));

        var LinqResult = Linq.ToArray();

        if (LinqResult != null && LinqResult.Any())
        {
          result = UserMapping.Map(LinqResult).ToList();
        }
      }
      return result.ToArray();
    }

    public static UserDTO[] SaveUsers(UserDTO[] data)
    {
      if (data == null) throw new FaultException(new FaultReason(""), new FaultCode("S0005"));
      List<UserDTO> result = new List<UserDTO>();

      using (MIMASEntities db = new MIMASEntities())
      {
        DbSet<User> UserSet = db.Set<User>();
        var UserIds = data.Select(x => x.Id).Distinct().ToArray();
        var Linq = from u in UserSet select u;

        if (UserIds != null && UserIds.Any())
          Linq = Linq.Where(x => UserIds.Contains(x.Id));

        var LinqResult = Linq.ToArray();

        using (var transaction = db.Database.BeginTransaction())
        {
          foreach (var item in data)
          {
            if (item.Id == 0 && item.IsDeleted) continue;

            #region Validations

            if (!userIsValid(item)) throw new FaultException(new FaultReason(""), new FaultCode("S0006"));
            if (UserSet.Any(x => x.Id != item.Id && x.EMail == item.EMail)) throw new FaultException(new FaultReason(""), new FaultCode("S0007"));
            if (UserSet.Any(x => x.Id != item.Id && x.Username == item.Username)) throw new FaultException(new FaultReason(""), new FaultCode("S0008"));
            if (!string.IsNullOrEmpty(item.CellarNo) && UserSet.Any(x => x.Id != item.Id && x.CellarNo == item.CellarNo)) throw new FaultException(new FaultReason(""), new FaultCode("S0009"));

            #endregion Validations

            User savedItem;

            if (item.Id > 0)
              savedItem = Linq.FirstOrDefault(x => x.Id == item.Id);
            else
            {
              savedItem = new User();
              UserSet.Add(savedItem);
            }

            if (!item.IsDeleted)
            {
              savedItem = UserMapping.Map(item);
              db.SaveChanges();
              item.Id = savedItem.Id;
              result.Add(item);
            }
            else
            {
              UserSet.Remove(savedItem);
              db.SaveChanges();
            }
          }
          transaction.Commit();
        }
      }

      return null;
    }

    private static bool userIsValid(UserDTO data)
    {
      bool result = true;

      if (string.IsNullOrEmpty(data.Username)) result = false;
      if (string.IsNullOrEmpty(data.Password)) result = false;
      if (string.IsNullOrEmpty(data.EMail)) result = false;

      return result;
    }



    public static UserBanListDTO[] SearchUserBanList(UserBanListCO criteria)
    {
      if (criteria == null) criteria = new UserBanListCO();
      List<UserBanListDTO> result = new List<UserBanListDTO>();

      using (MIMASEntities db = new MIMASEntities())
      {
        DbSet<UserBanList> UserBanListSet = db.Set<UserBanList>();

        var Linq = from ubl in UserBanListSet select ubl;

        if (criteria.UserBanListIds != null && criteria.UserBanListIds.Any())
          Linq = Linq.Where(x => criteria.UserBanListIds.Contains(x.Id));

        if (criteria.UserIds != null && criteria.UserIds.Any())
          Linq = Linq.Where(x => criteria.UserIds.Contains(x.UserId));

        if (criteria.BanType.HasValue)
          Linq = Linq.Where(x => x.BanTypeId == (int)criteria.BanType);

        if (criteria.IsBanned)
          Linq = Linq.Where(x => x.StartDate <= DateTime.Now && DateTime.Now <= x.EndDate);

        var LinqResult = Linq.ToArray();

        if (LinqResult != null && LinqResult.Any())
        {
          result = UserBanListMapping.Map(LinqResult).ToList();
        }
      }
      return result.ToArray();
    }

    public static UserBanListDTO[] SaveUserBanList(UserBanListDTO[] data)
    {
      List<UserBanListDTO> result = new List<UserBanListDTO>();

      using (MIMASEntities db = new MIMASEntities())
      {
        DbSet<UserBanList> UserBanListSet = db.Set<UserBanList>();

        var UserBanListIds = data.Where(x => x.Id > 0).Select(x => x.Id).Distinct().ToArray();
        var Linq = from ubl in UserBanListSet select ubl;

        if (UserBanListIds != null && UserBanListIds.Any())
          Linq = Linq.Where(x => UserBanListIds.Contains(x.Id));

        var LinqResult = Linq.ToArray();

        using (var transaction = db.Database.BeginTransaction())
        {
          foreach (var item in data)
          {
            if (item.Id == 0 && item.IsDeleted) continue;

            #region Validations

            if (!userBanListIsValid(item)) throw new FaultException(new FaultReason(""), new FaultCode("S0012"));

            #endregion Validations

            UserBanList savedItem;

            if (item.Id > 0)
              savedItem = Linq.FirstOrDefault(x => x.Id == item.Id);
            else
            {
              savedItem = new UserBanList();
              UserBanListSet.Add(savedItem);
            }

            if (!item.IsDeleted)
            {
              savedItem = UserBanListMapping.Map(item);
              db.SaveChanges();
              item.Id = savedItem.Id;
              result.Add(item);
            }
            else
            {
              UserBanListSet.Remove(savedItem);
              db.SaveChanges();
            }
          }
          transaction.Commit();
        }
      }
      return result.ToArray();
    }

    private static bool userBanListIsValid(UserBanListDTO data)
    {
      bool result = true;

      if (data == null) result = false;
      if (string.IsNullOrEmpty(data.Explanation)) result = false;
      if (data.UserId == 0) result = false;
      if (data.EndDate == default(DateTime)) result = false;
      if (data.StartDate == default(DateTime)) result = false;

      return result;
    }
  }
}
